#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
//#include <sys/stat.h>
#include <time.h>

#define MAX_PATH 260
#define BUFFER_SIZE 4096

clock_t start_time;

void create_path(const char *path) {
    char temp[MAX_PATH];
    char *p = NULL;
    size_t len;

    snprintf(temp, sizeof(temp), "%s", path);
    len = strlen(temp);
    
    if (temp[len - 1] == '\\')
        temp[len - 1] = 0;

    for (p = temp + 1; *p; p++) {
        if (*p == '\\') {
            *p = 0;
            mkdir(temp);
            *p = '\\';
        }
    }
    mkdir(temp);
}

void rle_decompress(FILE *input, FILE *output, long compressed_size) {
    unsigned char count_byte;
    long bytes_processed = 0;

    while (bytes_processed < compressed_size) {
        if (fread(&count_byte, 1, 1, input) != 1) break;
        bytes_processed++;

        if (count_byte & 0x80) {
            int repeat_count = (count_byte & 0x7F) + 1;
            unsigned char value;
            if (fread(&value, 1, 1, input) != 1) break;
            bytes_processed++;

            for (int i = 0; i < repeat_count; i++) {
                fwrite(&value, 1, 1, output);
            }
        } else {
            int non_repeat_count = count_byte + 1;
            unsigned char buffer[127];
            if (fread(buffer, 1, non_repeat_count, input) != non_repeat_count) break;
            bytes_processed += non_repeat_count;

            fwrite(buffer, 1, non_repeat_count, output);
        }
    }
}

int main(int argc, char *argv[]) {
    if (argc != 2) {
        printf("Usage: rleunzip <input>\n");
        return 1;
    }

    start_time = clock();
    const char *input_path = argv[1];
    FILE *input = fopen(input_path, "rb");
    if (!input) {
        perror("Failed to open input file");
        return 1;
    }

    char header[5] = {0};
    fread(header, 1, 4, input);
    if (strcmp(header, "RLEZ") != 0) {
        printf("Invalid RLEZ file format\n");
        fclose(input);
        return 1;
    }

    int num_files;
    fread(&num_files, sizeof(int), 1, input);

    long total_original_size = 0;
    long total_compressed_size = 0;

    for (int i = 0; i < num_files; i++) {
        int path_len;
        fread(&path_len, sizeof(int), 1, input);
        
        char path[MAX_PATH] = {0};
        fread(path, 1, path_len, input);
        
        long file_size;
        fread(&file_size, sizeof(long), 1, input);
        
        int is_dir;
        fread(&is_dir, sizeof(int), 1, input);

        if (is_dir) {
            create_path(path);
            continue;
        }

        char *last_slash = strrchr(path, '\\');
        if (last_slash) {
            *last_slash = '\0';
            create_path(path);
            *last_slash = '\\';
        }

        FILE *output = fopen(path, "wb");
        if (!output) {
            perror("Failed to create output file");
            continue;
        }

        rle_decompress(input, output, file_size);
        fclose(output);

        total_original_size += file_size;
        total_compressed_size += ftell(input);
    }

    fclose(input);
    clock_t end_time = clock();

    double time_used = ((double)(end_time - start_time)) / CLOCKS_PER_SEC;
    
    printf("Decompression completed:\n");
    printf("  Original size: %ld bytes\n", total_original_size);
    printf("  Compressed size: %ld bytes\n", total_compressed_size);
    printf("  Time used: %.2f seconds\n", time_used);

    return 0;
}
